package org.koin.core.instance;

import org.koin.core.Koin;
import org.koin.core.definition.BeanDefinition;
import org.koin.core.logger.Level;
import org.koin.core.parameter.DefinitionParameters;

/**
 * Koin Instance Holder
 * create/get/release an instance of given definition
 */
public abstract class InstanceFactory<T> {

    public static final String ERROR_SEPARATOR = "\n\t";

    private Koin koin;
    private BeanDefinition<T> beanDefinition;

    public InstanceFactory(Koin koin, BeanDefinition<T> beanDefinition) {
        this.koin = koin;
        this.beanDefinition = beanDefinition;
    }

    /**
     * Retrieve an instance
     *
     * @param context
     * @return T
     */
    public abstract T get(InstanceContext context);

    public T create(InstanceContext context) {

        if (koin.getLogger().isAt(Level.DEBUG)) {
            koin.getLogger().debug("| create instance for " + beanDefinition);
        }
        DefinitionParameters parameters = context.getParameters();
        context.getScope().addParameters(parameters);
        T value = beanDefinition.getDefinition().invoke(context.getScope(), parameters);
        context.getScope().clearParameters();
        return value;
    }

    /**
     * Is instance created
     */
    public abstract boolean isCreated();

    /**
     * Drop the instance
     */
    public abstract void drop();

    public BeanDefinition<T> getBeanDefinition() {
        return beanDefinition;
    }

    public void setBeanDefinition(BeanDefinition<T> beanDefinition) {
        this.beanDefinition = beanDefinition;
    }
}
